#pragma once
// 这是有关堵塞队列的生产者消费者模型
#include <iostream>
#include <pthread.h>
#include <queue>
#include "Mutex.hpp"
#include<unistd.h>
using namespace std;
const int num = 1; // 默认容量等于1
template <class T>
class BlockingQueue
{
private:
    bool IsEmpty()
    {
        return _bq.empty();
    }
    bool IsFull()
    {
        return _bq.size() == _cap;
    }

public:
    BlockingQueue(int cap = num) : _cap(cap)
    {
        _productor_wait_num = 0;
        _consumer_wait_num = 0;
        pthread_cond_init(&_full_cond, nullptr);
        pthread_cond_init(&_empty_cond, nullptr);
    }
    void ProSc(const T &x)
    {
        // 首先在生成时需要判断是否为满，并且在判断时也需要保持原子性
            Steward gl(_mutex); // 加锁
            while (IsFull())    // 要使用while一直判断，防止其他线程减减完之后，
            {
                _productor_wait_num++;                   // 因为此时已经满了，那么就要让线程进入等待
                pthread_cond_wait(&_full_cond, _mutex.GetMutex()); // 等待过程中就要将锁先解开,等待消费者先消费
                // 等待成功
                _productor_wait_num--;
            }
            // 此时就肯定是不满的
            _bq.push(x);
            // 生成成功之后就通知消费者来拿数据
            if (_consumer_wait_num > 0) // 等待的消费者>0
            {
                pthread_cond_signal(&_empty_cond);
            }
    }
    // 消费者消费产品
    void ConXf(T *x)
    {
        Steward gl(_mutex); // 加锁
            while (IsEmpty())
            {
                // 为空的话就消费者就等待生产者生成
                _consumer_wait_num++;
                pthread_cond_wait(&_empty_cond, _mutex.GetMutex());
                _consumer_wait_num--;
            }
            // 肯定不为空
            *x = _bq.front();
            _bq.pop();
            // 消费完一个产品就通知生产者生成
            if (_productor_wait_num > 0)
            {
                pthread_cond_signal(&_full_cond);
            }
    }
    ~BlockingQueue()
    {
        pthread_cond_destroy(&_full_cond);
        pthread_cond_destroy(&_empty_cond);
    }

private:
    int _cap; // 堵塞队列的容量
    Mutex _mutex;
    queue<T> _bq;
    pthread_cond_t _full_cond;  // 生产者条件变量
    pthread_cond_t _empty_cond; // 消费者条件变量

    int _productor_wait_num;
    int _consumer_wait_num;
};
